﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using dotsoftRAID_API;

namespace dotsoftRAID_Controller.RAIDControllers
{
    public abstract class RAID
    {
        private string dev0;
        private string[] RAID_DEVICES;

        public RAID(string dev0, string[] RAID_DEVICES)
        {
            this.dev0 = dev0;
            this.RAID_DEVICES = RAID_DEVICES;
        }

        public void Deinstall()
        {
           
        }

        protected virtual void ProcessRAID(FileSystemEventArgs args) { }

        /// <summary>
        /// Initializes the RAID Controller.
        /// </summary>
        /// <returns></returns>
        public virtual bool Initialize()
        {
            Logging.EnterMethod();

            DriveInfo[] drives = DriveInfo.GetDrives();

            //Check if the RAID Drives are available
            foreach (string device in RAID_DEVICES)
            {
                try
                {
                    DriveInfo dev = new DriveInfo(device);

                    DriveInfo driveQuery = (from drive in drives
                                            where drive.RootDirectory.FullName == dev.RootDirectory.FullName
                                            select drive).SingleOrDefault();

                    if (driveQuery == null)
                    {
                        DriveNotConnected(device);
                        return false;
                    }
                }
                catch (Exception)
                {
                    DriveNotConnected(device);
                    return false;
                }
            }

            Logging.ExitMethod();

            return true;
        }

        private void DriveNotConnected(string device)
        {
            Logging.EnterMethod();
            Process(string.Format("The drive '{0}' is not connected!", device));
            Stop(); 
            Logging.ExitMethod();
        }

        public virtual void Stop()
        {
            Process("RAID Controller stopped.");
        }
 
        public delegate void ProcessHandler(string message);
        public event ProcessHandler Process;

        protected void ProcessMessage(string message)
        {
            Process(message);
        }

        protected virtual void ChangeProcess(object sender, FileSystemEventArgs e)
        {
            if (Process != null)
                Process(string.Format("{0}: Changed '{1}'", DateTime.Now, e.FullPath));
        }

        protected virtual void CreatedProcess(object sender, FileSystemEventArgs e)
        {
            if (Process != null)
                Process(string.Format("{0}: Created '{1}'", DateTime.Now, e.FullPath));
        }

        protected virtual void DeletedProcess(object sender, FileSystemEventArgs e)
        {
            if (Process != null)
                Process(string.Format("{0}: Deleted '{1}'", DateTime.Now, e.FullPath));
        }

        protected virtual void RenamedProcess(object sender, RenamedEventArgs e)
        {
            if (Process != null)
                Process(string.Format("{0}: Renamed '{1}' to '{2}'", DateTime.Now, e.OldFullPath, e.FullPath));
        }

        /// <summary>
        /// Builds the path to the specified dev1 (RAID Device). Replaces the drive letter.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="dev1"></param>
        /// <returns></returns>
        protected string BuildPathToRAIDSystem(string path, string dev1)
        {
            Logging.EnterMethod();
            string[] splittedPath = path.Split(new string[] { @"\" }, StringSplitOptions.None);
            splittedPath[0] = string.Empty;
            string pathToRAID = string.Format(@"{0}\", dev1);

            for (int i = 0; i < splittedPath.Length; i++)
            {
                pathToRAID += string.Format("{0}{1}", splittedPath[i], (splittedPath[i] != string.Empty && i < (splittedPath.Length - 1)) ? @"\" : string.Empty);
            }
            Logging.ExitMethod();
            return pathToRAID;
        }

        /// <summary>
        /// Creates a directory if it does not exist.
        /// </summary>
        /// <param name="path"></param>
        protected void CreateDirectories(string path)
        {
            Logging.EnterMethod();
            string[] pathSplit = path.Split(new string[] { @"\" }, StringSplitOptions.None);

            pathSplit[pathSplit.Length - 1] = string.Empty;

            string tmpPath = string.Join(@"\", pathSplit);

            if (!Directory.Exists(tmpPath))
            {
                Directory.CreateDirectory(tmpPath);
            }
            Logging.ExitMethod();
        }

        /// <summary>
        /// Copies a file using FileStream.
        /// </summary>
        /// <param name="sourceFile"></param>
        /// <param name="destinationFile"></param>
        protected void CopyFile(string sourceFile, string destinationFile)
        {
            Logging.EnterMethod();
            try
            {
                API.UnlockFile(sourceFile);

                FileStream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read);
                FileStream destinationStream = new FileStream(destinationFile, FileMode.Create, FileAccess.Write);

                Byte[] streamBuffer = new Byte[sourceStream.Length];

                sourceStream.Read(streamBuffer, 0, streamBuffer.Length);
                destinationStream.Write(streamBuffer, 0, streamBuffer.Length);

                sourceStream.Close();
                destinationStream.Close();

                Console.WriteLine("Copy completed.");
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            }
            finally
            {
                Logging.ExitMethod();
            }
        }

        /// <summary>
        /// Returns true if the given path is a file.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        protected bool IsFile(string path)
        {
            return Path.GetExtension(path) != string.Empty;
        }

        /// <summary>
        /// Renames a file or a directory.
        /// </summary>
        /// <param name="oldName"></param>
        /// <param name="newName"></param>
        protected void RenameFileOrDir(string oldName, string newName)
        {
            Logging.EnterMethod();

            if (IsFile(oldName))
            {
                File.Move(oldName, newName);
            }
            else
            {
                Directory.Move(oldName, newName);
            }

            Logging.ExitMethod();
        }
    }
}
